<template>
    <div class="fs-wrap" :style="{ '--fs-left': leftWidth }">
      <!-- 左侧功能列表 -->
      <aside class="fs-aside">
        <div v-if="title" class="fs-aside-title">{{ title }}</div>
  
        <div v-if="searchable" class="fs-search">
          <input v-model="kw" type="text" placeholder="搜索功能…" />
        </div>
  
        <ul class="fs-menu" role="tablist">
          <li
            v-for="it in filtered"
            :key="it.key"
            :class="['fs-item', { active: it.key === currentKey, disabled: it.disabled }]"
            role="tab"
            :aria-selected="it.key === currentKey"
            @click="!it.disabled && select(it.key)"
          >
            <span class="fs-dot" :style="it.color ? { background: it.color } : {}"></span>
            <span class="fs-label" :title="it.label">{{ it.label }}</span>
            <span v-if="it.badge !== undefined" class="fs-badge">{{ it.badge }}</span>
          </li>
        </ul>
      </aside>
  
      <!-- 右侧内容 -->
      <section class="fs-content" role="tabpanel">
        <div class="fs-card">
          <header class="fs-card-head">
            <h3 class="fs-card-title">
              {{ active?.label || '未选择' }}
            </h3>
            <p v-if="active?.desc" class="fs-card-desc">{{ active.desc }}</p>
          </header>
  
          <!-- 插槽优先：完全自定义右侧 -->
          <slot name="content" :feature="active" v-if="$slots.content"></slot>
  
          <!-- 默认渲染：把 active.items 渲染为漂亮的字段块 -->
          <div v-else class="fs-grid">
            <template v-if="active?.items?.length">
              <div v-for="(txt, i) in active.items" :key="i" class="fs-chip" :title="txt">
                {{ txt }}
              </div>
            </template>
            <div v-else class="fs-empty">暂无内容</div>
          </div>
        </div>
      </section>
    </div>
  </template>
  
  <script setup>
  import { computed, ref, watch } from 'vue'
  
  const props = defineProps({
    /** 功能列表：[{ key,label,items?:string[],desc?,badge?,color?,disabled? }] */
    features: { type: Array, required: true },
    /** 受控/非受控：当前激活项 key */
    modelValue: { type: [String, Number], default: undefined },
    /** 初始激活项（非受控模式） */
    defaultActive: { type: [String, Number], default: undefined },
    /** 左侧面板宽度 */
    leftWidth: { type: String, default: '280px' },
    /** 左侧标题（可选） */
    title: { type: String, default: '' },
    /** 是否显示搜索框 */
    searchable: { type: Boolean, default: false },
  })
  
  const emit = defineEmits(['update:modelValue', 'change'])
  const innerKey = ref(props.defaultActive ?? props.features?.[0]?.key)
  const isControlled = computed(() => props.modelValue !== undefined)
  
  watch(
    () => props.modelValue,
    v => { if (isControlled.value) innerKey.value = v }
  )
  
  const currentKey = computed(() => (isControlled.value ? props.modelValue : innerKey.value))
  const active = computed(() => props.features.find(f => f.key === currentKey.value))
  
  function select(key) {
    if (!isControlled.value) innerKey.value = key
    emit('update:modelValue', key)
    emit('change', props.features.find(f => f.key === key) || null)
  }
  
  /* 搜索 */
  const kw = ref('')
  const filtered = computed(() => {
    if (!kw.value.trim()) return props.features
    const k = kw.value.trim().toLowerCase()
    return props.features.filter(f => f.label.toLowerCase().includes(k))
  })
  </script>
  
  <style scoped>
  .fs-wrap{
    --fs-left: 280px;
    display: grid;
    grid-template-columns: var(--fs-left) 1fr;
    gap: 16px;
  }
  .fs-aside{
    background: #fff;
    border-radius: 16px;
    padding: 14px;
    box-shadow: 0 4px 16px rgba(0,0,0,.06);
    height: 100%;
  }
  .fs-aside-title{
    font-weight: 600;
    padding: 4px 2px 10px;
  }
  .fs-search input{
    width: 100%;
    height: 34px;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 0 10px;
    outline: none;
  }
  .fs-menu{
    list-style: none;
    margin: 10px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 60vh;
    overflow: auto;
  }
  .fs-item{
    display: grid;
    grid-template-columns: 14px 1fr auto;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 12px;
    cursor: pointer;
    transition: .2s ease;
    color: #374151;
  }
  .fs-item:hover{ background: #f3f4f6; }
  .fs-item.active{
    background: #eef2ff;
    color: #4338ca;
    box-shadow: inset 0 0 0 1px rgba(99,102,241,.25);
  }
  .fs-item.disabled{
    opacity:.5; cursor:not-allowed;
  }
  .fs-dot{
    width: 8px; height: 8px; border-radius: 999px; background: #d1d5db;
  }
  .fs-label{
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .fs-badge{
    font-size: 12px; padding: 2px 6px; border-radius: 999px;
    background: #f1f5f9; color:#475569;
  }
  
  /* 右 */
  .fs-content{}
  .fs-card{
    background:#fff; border-radius:16px; padding:18px;
    box-shadow: 0 8px 24px rgba(0,0,0,.06);
    min-height: 280px;
  }
  .fs-card-head{ margin-bottom: 12px; }
  .fs-card-title{ margin:0; font-size:18px; font-weight:700; }
  .fs-card-desc{ margin:6px 0 0; color:#6b7280; }
  
  .fs-grid{
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 10px;
    margin-top: 10px;
  }
  .fs-chip{
    background: #f8fafc;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    padding: 10px 12px;
    font-size: 13px;
    line-height: 1.3;
    white-space: normal;
    word-break: break-word;
  }
  .fs-empty{
    color:#94a3b8; padding: 20px 0;
  }
  </style>
  